﻿///////////////////////////////////////////////////////////////////////////////
//
// This file is part of the BassDrop project
//   https://code.google.com/p/bass-drop/
//
//
// Creator:	Gergely Krajcsovszki (krajcsovszkig@hotmail.com)
// Date:	2013-12-05 18:20
//
//
// Copyright © 2013-2014. Gergely Krajcsovszki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BassDrop.Core.Common.Data.IO.Data;
using BassDrop.Core.Common.Media;
using BassDrop.Core.Common.Media.Playlists;
using BassDrop.Core.Common.Services;

namespace BassDrop.Core.Common.Data.IO
{
	/// <summary>
	/// Provides utility methods for media file handling, eg. lookup, validation, etc.
	/// </summary>
	public static class MediaIO
	{
		// TODO: localPath-ekkel gondok lehetnek
		// csak külső playlistek esetén van értelme, exportáláskor kéne csak belerakni, a betöltött mediatrackekbe ne menjen bele

		/// <summary>
		/// Finds or creates a playlist item (eg. media track) matching the data in the passed resource location
		/// </summary>
		/// <param name="resourceLocation"></param>
		/// <returns></returns>
		public static PlaylistItemBase GetOrCreatePlaylistItemFor( ResourceLocation resourceLocation )
		{
			// TODO: copy, expand with other known info
			// legyen libraryban egy relativepath lista, ezt adja hozzá minden resourcelocationhoz, az implicit az app workingdirje legyen

			foreach ( var item in resourceLocation.GetPossibleIds( Controller.AppName, Controller.MachineId ) )
			{
				long id;

				if ( long.TryParse( item, out id ) && id > 1000 )
				{
					return null; // TODO: actionitemek, robusztusabb feltétel
				}
			}

			return new PlaylistItemMediaTrack( MediaTrack.ForLocation( resourceLocation ) );
		}

		/// <summary>
		/// Returns the resource location of the passed playlist item (eg. media track).
		/// The resource location stored inside it will be expanded by the known locations for this client / application and location / machine.
		/// </summary>
		/// <param name="playlistItem"></param>
		/// <returns></returns>
		public static ResourceLocation GetResourceLocationOf( PlaylistItemBase playlistItem )
		{
			var mediaTrack = playlistItem as PlaylistItemMediaTrack;

			if ( mediaTrack != null )
			{
				return mediaTrack.Track.MediaLocation; // TODO: copy, expand with other known info
				// legyen libraryban egy relativepath lista, ezt adja hozzá minden resourcelocationhoz
				// key!
			}

			return null; // TODO: actionitemek
		}

		/// <summary>
		/// Gets all the valid absolute URIs of the file pointed to by the passed ResourceLocation on this device
		/// </summary>
		/// <param name="resourceLocation"></param>
		/// <returns></returns>
		public static IEnumerable<Uri> GetValidAbsoluteUrisFrom( ResourceLocation resourceLocation )
		{
			foreach ( var item in resourceLocation.GetPossibleIds( Controller.AppName, Controller.MachineId ) )
			{
				// TODO: if library[id].GetValidAbsoluteUri() != null, return it
			}

			foreach ( var item in resourceLocation.GetPossibleAbsoluteUris( Controller.AppName, Controller.MachineId ) )
			{
				if ( CheckFile( item.LocalPath, resourceLocation.Key ) ) // TODO: metát ne tesztelje?
				{
					yield return item;
				}
			}
		}

		/// <summary>
		/// Gets the absolute URI of the file pointed to by the passed ResourceLocation on this device,
		/// or null if it cannot be found.
		/// </summary>
		/// <param name="resourceLocation"></param>
		/// <returns></returns>
		public static Uri GetValidAbsoluteUriFrom( ResourceLocation resourceLocation )
		{
			return GetValidAbsoluteUrisFrom( resourceLocation ).FirstOrDefault();
		}

		/// <summary>
		/// Finds or creates a ResourceLocation for the file on the passed absolute URI
		/// </summary>
		/// <param name="uri"></param>
		/// <returns></returns>
		public static ResourceLocation GetOrCreateResourceLocationForUri( Uri uri )
		{
			// TODO: BassDrop.Core.Common.Data.IO.MediaIO.GetOrCreateResourceLocationForUri(Uri uri)
			// keressen rá a libraryban és a betöltött fájlok között, egyébként csináljon neki relatív és local utakat, ha tud és keyt is
			// esetleg ha talál valamit, akkor nem is kéne locationnel játszani, hanem egyből vissza lehetne adni azt
			var location = new ResourceLocation( Controller.WorkingDir, null );

			var path = new ResourceLocation.ResourceLocationInfoAbsolutePath( uri, location );
			path.LocationIds.Add( Controller.MachineId );
			location.AbsolutePaths.Add( path );

			location.Key.Hash = new Hash( ServiceCenter.FileHandler.GetMD5Hash( uri.LocalPath ), "md5" );

			return location;
		}

		/// <summary>
		/// Checks if the passed file is valid and matches the passed key
		/// </summary>
		/// <param name="file"></param>
		/// <param name="key"></param>
		/// <returns></returns>
		public static bool CheckFile( string file, MediaKey key )
		{
			if ( file == null || !ServiceCenter.FileHandler.Exists( file ) )
			{
				return false;
			}

			if ( key == null )
			{
				return true;
			}

			if ( key.Hash != null && !CheckHash( file, key.Hash ) )
			{
				return false;
			}

			return true;
			// TODO: mást is ellenőrizni
		}

		/// <summary>
		/// Checks if the passed file matches the passed hash
		/// </summary>
		/// <param name="file"></param>
		/// <param name="hash"></param>
		/// <returns></returns>
		public static bool CheckHash( string file, Hash hash )
		{
			switch ( hash.Algorithm )
			{
				case "md5":
					return hash.HashCode == ServiceCenter.FileHandler.GetMD5Hash( file );
				default:
					// TODO: ilyenkor mi legyen ?
					return true;
			}
		}
	}
}
